package com.practice.java;

import java.io.*;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 使用前注意：此类只做<dependency></dependency>标签的处理
 * 需要将groupId, artifactId等中类似${project.id}的值预先替换
 */
public class Practice1MergeMavenPom {
    //双重检查锁定
    private static volatile Practice1MergeMavenPom INSTANCE;
    public static void main(String[] args) {
        getINSTANCE().resolveMergePom();
    }
    public static Practice1MergeMavenPom getINSTANCE() {
        if(INSTANCE == null) {
            synchronized (Practice1MergeMavenPom.class) {
                if(INSTANCE == null) {
                    INSTANCE = new Practice1MergeMavenPom();
                }
            }
        }
        return INSTANCE;
    }
    public void resolveMergePom() {
        final String patternString = "<dependency>\\s+?<groupId>([\\w.-]+?)</groupId>\\s+?<artifactId>([\\w.-]+?)</artifactId>"
                + "([\\s\\w.</>]+?)</dependency>";
        final String contentPatternString = "<(\\w+?)>([\\w.-]+?)</\\w+?>";
        Pattern pattern = Pattern.compile(patternString), contentPattern = Pattern.compile(contentPatternString);
        String pom1String = readPomFile("D:\\Users\\Adam\\Documents\\Coding\\code_practice_2024\\java\\resources\\practice1MergeMavenPom\\pom1.xml"),
                pom2String = readPomFile("D:\\Users\\Adam\\Documents\\Coding\\code_practice_2024\\java\\resources\\practice1MergeMavenPom\\pom2.xml");
        Map<KVPair<String,String>, KVPair<Boolean,List<KVPair<String,String>>>> dependencyMap = new HashMap<>();
        extractFromPom(pom1String, pattern, contentPattern, dependencyMap);
        extractFromPom(pom2String, pattern, contentPattern, dependencyMap);

        String mergedPomString = getMergedPomString(dependencyMap);
//        System.out.println(mergedPomString);
        writePomFile("D:\\Users\\Adam\\Documents\\Coding\\code_practice_2024\\java\\resources\\practice1MergeMavenPom\\mergedPom.xml", mergedPomString);

        readFromClasspath("/practice1MergeMavenPom/mergedPom.xml");
    }
    private void extractFromPom(String pomString, Pattern pattern, Pattern contentPattern, Map<KVPair<String,String>, KVPair<Boolean,List<KVPair<String,String>>>> dependencyMap) {
        assert pomString!=null;
        Matcher matcher = pattern.matcher(pomString);
        while(matcher.find()) {
            String gId = matcher.group(1), aId = matcher.group(2), content = matcher.group(3);
//            System.out.println("gId:"+gId + " aId:" + aId+ " content:"+content);
            Matcher contentMatcher = contentPattern.matcher(content);
            KVPair<String, String> kvPair = new KVPair<>(gId, aId);
            List<KVPair<String, String>> kvPairList = new LinkedList<>();
            while(contentMatcher.find()) {
                String contentKey = contentMatcher.group(1), contentValue = contentMatcher.group(2);
//                System.out.println("key:"+contentKey + " value:"+contentValue);
                kvPairList.add(new KVPair<>(contentKey, contentValue));
            }
            if(dependencyMap.containsKey(kvPair)) {
                dependencyMap.get(kvPair).value.addAll(kvPairList);
                dependencyMap.get(kvPair).key = true;
            } else {
                dependencyMap.put(kvPair, new KVPair<>(false, kvPairList));
            }
        }
    }
    private String getMergedPomString(Map<KVPair<String,String>, KVPair<Boolean, List<KVPair<String,String>>>> dependencyMap) {
        StringBuilder mergedPomStringBuilder = new StringBuilder();
        for(Map.Entry<KVPair<String,String>,KVPair<Boolean,List<KVPair<String,String>>>> entry: dependencyMap.entrySet()) {
//            System.out.println(entry);
            KVPair<String,String> gaId = entry.getKey();
            boolean duplicated = entry.getValue().key;
            List<KVPair<String,String>> contentList = entry.getValue().value;
            mergedPomStringBuilder.append("<dependency>").append(System.lineSeparator());
            if(duplicated) {
                mergedPomStringBuilder.append("    <!-- TODO DUPLICATE ARTIFACT -->").append(System.lineSeparator());
            }
            mergedPomStringBuilder.append("    <groupId>").append(gaId.key).append("</groupId>").append(System.lineSeparator())
                    .append("    <artifactId>").append(gaId.value).append("</artifactId>").append(System.lineSeparator());
            for(KVPair<String,String> content : contentList) {
                mergedPomStringBuilder.append("    <").append(content.key).append(">").append(content.value).append("</")
                        .append(content.key).append(">").append(System.lineSeparator());
            }
            mergedPomStringBuilder.append("</dependency>").append(System.lineSeparator());
        }
        return mergedPomStringBuilder.toString();
    }
    class KVPair<K,V> {
        private K key;
        private V value;
        public KVPair(K key, V value) {
            this.key = key;
            this.value = value;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            KVPair kvPair = (KVPair) o;
            return Objects.equals(key, kvPair.key) && Objects.equals(value, kvPair.value);
        }

        @Override
        public int hashCode() {
            return Objects.hash(key, value);
        }

        @Override
        public String toString() {
            return "KVPair{" +
                    "key=" + key +
                    ", value=" + value +
                    '}';
        }
    }
    private String readPomFile(String pomFilePath) {
        FileReader fileReader = null;
        try {
            fileReader = new FileReader(pomFilePath);
            char[] buffer = new char[128];
            int bytesRead;
            StringBuilder stringBuilder = new StringBuilder();
            while ((bytesRead = fileReader.read(buffer)) != -1) {
                stringBuilder.append(buffer, 0, bytesRead);
            }
            return stringBuilder.toString();
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        } finally {
            if(fileReader != null) {
                try {
                    fileReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    private void writePomFile(String pomFilePath, String pomString) {
        FileWriter fileWriter = null;
        try {
            fileWriter = new FileWriter(pomFilePath);
            fileWriter.write(pomString);
        } catch (IOException exception) {
            exception.printStackTrace();
        } finally {
            if(fileWriter != null) {
                try {
                    fileWriter.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 从Classpath路径下读取文件
     * @param fileName
     */
    private void readFromClasspath(String fileName) {
        InputStream inputStream = Practice1MergeMavenPom.class.getResourceAsStream(fileName);
        byte[] buffer = new byte[128];
        int len;
        StringBuilder stringBuilder = new StringBuilder();
        try {
            while ((len = inputStream.read(buffer, 0, 128)) != -1) {
                int i = 0;
                while (i < len) {
                    stringBuilder.append((char) buffer[i]);
                    i++;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println(stringBuilder);
    }
}
